#include "OpenglAppFramework/inc/PlugIn/LODPlugIn.h"
#include "OpenglAppFramework/inc/Shader.h"
#include "OpenglAppFramework/inc/GameObject.h"
#include "OpenglAppFramework/inc/Scene.h"
#include "OpenglAppFramework/inc/SceneConfig.h"
#include "OpenglAppFramework/inc/Utils.h"
#include "OpenglAppFramework/inc/glm/glm.hpp"
#include "OpenglAppFramework/inc/glm/gtc/matrix_transform.hpp"
#include "OpenglAppFramework/inc/glm/gtc/type_ptr.hpp"
#include <iostream>

LODPlugIn::LODPlugIn(const std::string& name) :
    PlugIn(name, PlugInType::LOD) {
    m_cur_lod_level = 0;
    m_main_cam = nullptr;
}

LODPlugIn::~LODPlugIn() {}

int LODPlugIn::setConfigData(const nlohmann::json& data) {
    m_cam_name = data["camera_object_name"];
    LODItemGroup group;
    PlugInType type;

    for(auto js : data["lod_group"]) {
        m_dist_list.push_back(js["distance"].get<float>());
        group.clear();
        for(auto item_js : js["items"].items()) {
            type = string2PlugInType(item_js.key());
            group[type] = {item_js.value(), nullptr}; 
            // 此时type对于的plugin的实例可能还没有创建好
            // 获取对应的plugin指针的工作放在init()中进行
        }
        m_lod_groups.push_back(group);
    }
    return 0;
}

int LODPlugIn::init() {
    // 获取主摄像机的指针
    m_main_cam = m_obj->scene()->getObjectByName(m_cam_name);
    if(m_main_cam == nullptr) {
        std::cout << "LOD no cam: " << m_cam_name << std::endl;
        return -1;
    }
    
    // 获取每个LOD相关的plugin的指针
    PlugIn* plugin;
    for(LODItemGroup& group : m_lod_groups) {
        for(auto kv : group) {
            plugin = m_obj->getPlugInByName(kv.second.first);
            if(plugin == nullptr) {
                std::cout << "LOD find plugin failed: " << kv.second.first << std::endl;
                return -1;
            }
            group[kv.first].second = plugin; // 遍历map改value会不会蹦???
        }
    }
    return 0;
}

void LODPlugIn::destroy() {}

void LODPlugIn::routine() {
    glm::vec4 obj_location = m_obj->modelMat() * glm::vec4(0, 0, 0, 1);
    glm::vec3 obj_location_v3 = {obj_location[0], obj_location[1], obj_location[2]};
    glm::vec4 cam_location = m_main_cam->modelMat() * glm::vec4(0, 0, 0, 1);
    glm::vec3 cam_location_v3 = {cam_location[0], cam_location[1], cam_location[2]};
    float distance = glm::distance(obj_location_v3, cam_location_v3);
    uint32_t idx; // 期望的lod等级
    for(idx = 0; idx < m_dist_list.size(); idx ++) {
        if(distance <= m_dist_list[idx]) {
            break;
        }
    }
    if(idx == m_dist_list.size()) {
        idx = m_dist_list.size() - 1;
    }
    if(idx != m_cur_lod_level) {
        // lod等级变化时，切换相应的plugin
        for(auto kv : m_lod_groups[idx]) {
            m_obj->changePlugIn(kv.second.second);
        }
        m_cur_lod_level = idx;
    }
    // std::cout << "dist:" << distance << "idx: " << idx <<" cur_lvl:"<< m_cur_lod_level<<std::endl;
}
